package com.glodon.paas.account.web.controller;

import com.glodon.paas.account.security.cas.notification.HttpCasNotificationManager;
import com.glodon.paas.account.security.common.PostAuthHandler;
import com.glodon.paas.account.security.spring.LoginUser;
import com.glodon.paas.account.web.listener.AuthenticatedSessionServerListener;
import com.glodon.paas.account.web.util.CookieUtils;
import org.jasig.cas.CentralAuthenticationService;
import org.jasig.cas.authentication.principal.Service;
import org.jasig.cas.authentication.principal.SimpleWebApplicationServiceImpl;
import org.jasig.cas.ticket.TicketException;
import org.jasig.cas.validation.Assertion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static com.google.common.base.Strings.isNullOrEmpty;

/**
 * Validate Service Ticket sent from Relaying Parties
 *
 * @author Don Li
 */
@Controller
@RequestMapping("/cas")
public class CasController {
    private static final Logger LOGGER = LoggerFactory.getLogger(CasController.class);

    @Value("${tgc.name}")
    private String tgcName;

    @Autowired
    private CentralAuthenticationService cas;

    @Autowired
    private PostAuthHandler postAuthHandler;

    @Autowired
    private HttpCasNotificationManager notificationManager;

    @RequestMapping("/serviceValidate")
    public ModelAndView validateServiceTicket(@RequestParam(value = "service", defaultValue = "unknown-service") String serviceId,
                                              @RequestParam("ticket") String ticket) {
        LOGGER.debug("do ST validation for ticket : {}, from service : {}", ticket, serviceId);
        Service service = new SimpleWebApplicationServiceImpl(serviceId);
        try {
            Assertion assertion = cas.validateServiceTicket(ticket, service);
            final ModelAndView success = new ModelAndView("casServiceValidationSuccess");
            success.addObject("assertion", assertion);
            return success;
        } catch (TicketException e) {
            LOGGER.error("ST validation failed", e);
        }
        final ModelAndView failure = new ModelAndView("casServiceValidationFailure");
        failure.addObject("code", 401);
        failure.addObject("description", "ST validation failed");
        return failure;
    }

    @RequestMapping(value = "/serviceLogout", method = RequestMethod.GET)
    public void logout(@RequestParam(value = "service", defaultValue = "unknown-service") String serviceId,
                       @RequestParam(value = "return_to") String returnTo,
                       HttpServletRequest request, HttpServletResponse response) throws IOException {
        LOGGER.debug("Processing sign out from service: {}", serviceId);
        String tgtId = CookieUtils.getValue(tgcName, request);
        if (!isNullOrEmpty(tgtId)) {
            // invalidate user sessions at all relaying parties
            LoginUser user = postAuthHandler.getUserByTgtId(tgtId);
            if (user != null) {
                // TODO: a barrier maybe required here if we want sync ops. and retry/timeout?
                AuthenticatedSessionServerListener.invalidateUserSessions(user.getId());
                notificationManager.sendInvalidateSessionNotification(serviceId, user);
            }
            // un-register the TGT
            cas.destroyTicketGrantingTicket(tgtId);
        }
        response.sendRedirect(returnTo);
    }
}
